home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 6 code / TCP / NewsWatcher / NW Source / Source / newswatcher.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-12  |  32.1 KB  |  1,446 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     newswatcher.c
  4.  
  5.     This module contains the main entry point of the program and the main 
  6.     event loop.
  7.     
  8.     Copyright © 1994-1995, Northwestern University.
  9.     
  10. ----------------------------------------------------------------------------*/
  11.  
  12.     
  13.     
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <ctype.h>
  17.  
  18. #include <CodeFragments.h>
  19.  
  20. #include "glob.h"
  21. #include "newswatcher.h"
  22. #include "about.h"
  23. #include "newsrc.h"
  24. #include "full.h"
  25. #include "prefsdlog.h"
  26. #include "menus.h"
  27. #include "news.h"
  28. #include "prefs.h"
  29. #include "print.h"
  30. #include "log.h"
  31. #include "net.h"
  32. #include "nntp.h"
  33. #include "message.h"
  34. #include "wind.h"
  35. #include "dialog.h"
  36. #include "aevt.h"
  37. #include "group.h"
  38. #include "subject.h"
  39. #include "article.h"
  40. #include "status.h"
  41. #include "text.h"
  42. #include "memutil.h"
  43. #include "spin.h"
  44. #include "windutil.h"
  45. #include "fileutil.h"
  46. #include "cache.h"
  47. #include "strutil.h"
  48. #include "resutil.h"
  49. #include "open.h"
  50. #include "teutil.h"
  51. #include "dummy.h"
  52. #include "sfutil.h"
  53. #include "drawutil.h"
  54. #include "ldef.h"
  55. #include "url.h"
  56. #include "subscribe.h"
  57. #include "ic.h"
  58. #include "genutil.h"
  59. #include "help.h"
  60.  
  61.  
  62.  
  63. /*#define testingOT    1*/
  64. #define OTTestHost    "cash.acns.nwu.edu"
  65. #define OTTestUser    "jln"
  66. #define OTTestPswd    "xxx"
  67. #define OTTestPath    "ottest"
  68. #define OTTestName    "\pottest"
  69. #define OTDelay        0
  70.  
  71.  
  72.  
  73. #define kNeedSystem7AlertID        500            /* need System 7.0 or later alert id */
  74. #define kTPrefRecSize            7960        /* preferences record size */
  75.  
  76. #define kErrorDuringQuitDlg                155
  77. #define kErrorDuringQuitDlgQuitItem        1
  78.  
  79. #define kWaitForDNRDlg        154                /* wait for DNR dialog */
  80. #define kRetryConnectID        166                /* retry news server connect dialog */
  81.  
  82.  
  83. static WindowPtr gMouseDownWindow = nil;    /* pointer to window in which mouse
  84.                                                down happened */
  85.  
  86.  
  87.  
  88. /*----------------------------------------------------------------------------
  89.     DoClose
  90.     
  91.     Close a window.
  92.     
  93.     Entry:    wind = pointer to window.
  94.     
  95.     Exit:    function result = error code.
  96. ----------------------------------------------------------------------------*/
  97.  
  98. OSErr DoClose (WindowPtr wind)
  99. {
  100.     TWindowKind kind;
  101.     GrafPtr port;
  102.     OSErr err = noErr;
  103.  
  104.     kind = GetMyWindowKind(wind);
  105.     if (kind != kNotOurWind) {
  106.         GetPort(&port);
  107.         SetPort(wind);
  108.         err = (*gDispatch[kind].close)(wind);
  109.         SetPort(port);
  110.     }
  111.     return err;
  112. }
  113.  
  114.  
  115.  
  116. /*----------------------------------------------------------------------------
  117.     DoZoom
  118.     
  119.     Zoom a window.
  120.     
  121.     Entry:    wind = pointer to window.
  122.             zoomDir = zoom direction = inZoomIn or inZoomOut.
  123.             
  124.     Exit:    function result = error code.
  125. ----------------------------------------------------------------------------*/
  126.  
  127.  
  128. OSErr DoZoom (WindowPtr wind, short zoomDir)
  129. {
  130.     TWindowKind kind;
  131.     GrafPtr port;
  132.     OSErr err = noErr;
  133.  
  134.     kind = GetMyWindowKind(wind);
  135.     if (kind != kNotOurWind) {
  136.         GetPort(&port);
  137.         SetPort(wind);
  138.         err = (*gDispatch[kind].zoom)(wind, zoomDir);
  139.         SetPort(port);
  140.     }
  141.     
  142.     return err;
  143. }
  144.  
  145.  
  146.  
  147. /*----------------------------------------------------------------------------
  148.     DoCommand
  149.     
  150.     Do a command.
  151.     
  152.     Entry:    mResult = 16/menu, 16/item.
  153.             modifiers = modifiers field from event record.
  154.             
  155.     Exit:    function result = error code.
  156.     
  157.     Commands which act on the frontmost window are dispatched to the
  158.     proper window handling module. Other commands are handled directly,
  159.     without invoking a window handling module.
  160. ----------------------------------------------------------------------------*/
  161.  
  162. static OSErr DoCommand (long mResult, short modifiers)
  163. {
  164.     short menu, item;
  165.     WindowPtr wind;
  166.     TWindowKind kind;
  167.     GrafPtr port;
  168.     Boolean commandHandled;
  169.     Str255 daName;
  170.     OSErr err = noErr;
  171.     
  172.     menu = HiWord(mResult);
  173.     item = LoWord(mResult);
  174.     
  175.     wind = FrontWindow();
  176.     kind = GetMyWindowKind(wind);
  177.     
  178.     commandHandled = true;
  179.     
  180.     switch (menu) {
  181.     
  182.         case kAppleMenu:
  183.         
  184.             switch (item) {
  185.                 case kAboutNewsWatcherItem:
  186.                     err = DoAboutNewsWatcher();
  187.                     break;
  188.                 default:
  189.                     GetPort(&port);
  190.                     SetCursor(&qd.arrow);
  191.                     GetMenuItemText(GetMenuHandle(kAppleMenu), item, daName);
  192.                     OpenDeskAcc(daName);
  193.                     SetPort(port);
  194.                     break;
  195.             }
  196.             break;
  197.             
  198.         case kFileMenu:
  199.         
  200.             switch (item) {
  201.                 case kNewGroupWindowItem:
  202.                     err = DoNewGroupWindow();
  203.                     break;
  204.                 case kOpenItem:
  205.                     err = DoOpen();
  206.                     break;
  207.                 case kCloseItem:
  208.                     err = DoClose(wind);
  209.                     break;
  210.                 case kPageSetupItem:
  211.                     err = DoPageSetup();
  212.                     break;
  213.                 case kPreferencesItem:
  214.                     err = DoPreferences();
  215.                     break;
  216.                 case kQuitItem:
  217.                     gDone = true;
  218.                     break;
  219.                 default:
  220.                     commandHandled = false;
  221.                     break;
  222.             }
  223.             break;
  224.             
  225.         case kEditMenu:
  226.         
  227.             commandHandled = false;
  228.             break;
  229.  
  230.         case kNewsMenu:
  231.         
  232.             switch (item) {
  233.                 case kNewMessageItem:
  234.                     err = DoNewMessage();
  235.                     break;
  236.                 default:
  237.                     commandHandled = false;
  238.                     break;
  239.             }
  240.             break;
  241.  
  242.         case kSpecialMenu:
  243.         
  244.             switch (item) {
  245.                 case kGetGroupListFromHostItem:
  246.                     err = DoGetGroupListFromHost();
  247.                     break;
  248.                 case kGetServerInfoItem:
  249.                     err = DoGetServerInfo();
  250.                     break;
  251.                 case kOpenURLItem:
  252.                     err = DoOpenURL(wind);
  253.                     break;
  254.                 case kCheckForNewGroupsItem:
  255.                     err = DoCheckForNewGroups();
  256.                     break;
  257.                 case kCheckForDeletedGroupsItem:
  258.                     err = DoCheckForDeletedGroups();
  259.                     break;
  260.                 case kRebuildFullGroupListItem:
  261.                     err = DoRebuildFullGroupList();
  262.                     break;
  263.                 default:
  264.                     commandHandled = false;
  265.                     break;
  266.             }
  267.             break;
  268.  
  269.         case kWindMenu:
  270.         
  271.             switch (item) {
  272.                 case kCycleWindowsItem:
  273.                     DoCycleWindows(wind);
  274.                     break;
  275.                 case kZoomWindowItem:
  276.                     err = DoZoomWindow(wind);
  277.                     break;
  278.                 case kShowHideFullGroupListItem:
  279.                     err = DoShowHideFullGroupList();
  280.                     break;
  281.                 default:
  282.                     SelectWindMenu(item);
  283.                     break;
  284.             }
  285.             break;
  286.             
  287.         case kHMHelpMenuID:
  288.         
  289.             err = DoHelpMenuCommand(item);
  290.             break;
  291.      }
  292.     
  293.     if (!commandHandled && kind != kNotOurWind) {
  294.         GetPort(&port);
  295.         SetPort(wind);
  296.         err = (*gDispatch[kind].command)(wind, menu, item, modifiers);
  297.         SetPort(port);
  298.     }
  299.      
  300.     HiliteMenu(0);
  301.     
  302.     return err;
  303. }
  304.  
  305.  
  306.  
  307. /*----------------------------------------------------------------------------
  308.     Draggable
  309.     
  310.     Determine whether a mouse down event is in a draggable object in a 
  311.     window.
  312.     
  313.     Entry:    wind = pointer to window.
  314.             where = location of mouse down event, in local coordinates.
  315.             modifiers = modifiers field from event record.
  316.             
  317.     Exit:    function result = true if object is draggable.
  318. ----------------------------------------------------------------------------*/
  319.  
  320. static Boolean Draggable (WindowPtr wind, Point where, short modifiers)
  321. {
  322.     GrafPtr port;
  323.     TWindowKind kind;
  324.     Boolean result = false;
  325.  
  326.     if (!gHaveDragMgr) return false;
  327.     kind = GetMyWindowKind(wind);
  328.     if (kind != kNotOurWind) {
  329.         GetPort(&port);
  330.         SetPort(wind);
  331.         result = (*gDispatch[kind].draggable)(wind, where, modifiers);
  332.         SetPort(port);
  333.     }
  334.     
  335.     return result;
  336. }
  337.  
  338.  
  339.  
  340. /*----------------------------------------------------------------------------
  341.     HandleGrow
  342.     
  343.     Handle a mouse down event in the grow box of a window.
  344.     
  345.     Entry:    wind = pointer to window.
  346.             where = location of mouse down event, in global coordinates.
  347.             
  348.     Exit:    function result = error code.
  349. ----------------------------------------------------------------------------*/
  350.  
  351. static OSErr HandleGrow (WindowPtr wind, Point where)
  352. {
  353.     GrafPtr port;
  354.     TWindowKind kind;
  355.     OSErr err = noErr;
  356.     
  357.     kind = GetMyWindowKind(wind);
  358.     if (kind != kNotOurWind) {
  359.         GetPort(&port);
  360.         SetPort(wind);
  361.         err = (*gDispatch[kind].grow)(wind, where);
  362.         SetPort(port);
  363.     }
  364.     
  365.     return err;
  366. }
  367.  
  368.  
  369.  
  370. /*----------------------------------------------------------------------------
  371.     HandleDrag
  372.     
  373.     Handle a window drag operation.
  374.     
  375.     Entry:    wind = pointer to window.
  376.             where = location of mouse down event, in global coordinates.
  377. ----------------------------------------------------------------------------*/
  378.  
  379. static void HandleDrag (WindowPtr wind, Point where)
  380. {
  381.     Rect r;
  382.     GrafPtr port;
  383.     Point oldTopLeft = {0, 0};
  384.     Point newTopLeft = {0, 0};
  385.     TWindow **info;
  386.  
  387.     GetPort(&port);
  388.     SetPort(wind);
  389.     LocalToGlobal(&oldTopLeft);
  390.     r = gDesktopExtent;
  391.     InsetRect(&r, 4, 4);
  392.     DragWindow(wind, where, &r);
  393.     LocalToGlobal(&newTopLeft);
  394.     if (oldTopLeft.h != newTopLeft.h || oldTopLeft.v != newTopLeft.v) {
  395.         if (GetMyWindowKind(wind) != kNotOurWind) {
  396.             info = (TWindow**)GetWRefCon(wind);
  397.             (**info).windPosValid = true;
  398.             (**info).movedSinceLastSave = true;
  399.         }
  400.     }
  401.     SetPort(port);
  402. }
  403.  
  404.  
  405.  
  406. /*----------------------------------------------------------------------------
  407.     HandleActivate
  408.     
  409.     Activate or deactivate a window.
  410.     
  411.     Entry:    wind = pointer to window.
  412.             act = true to activate, false to deactivate.
  413. ----------------------------------------------------------------------------*/
  414.  
  415. void HandleActivate (WindowPtr wind, Boolean act)
  416. {
  417.     GrafPtr port;
  418.     TWindowKind kind;
  419.  
  420.     kind = GetMyWindowKind(wind);
  421.     if (kind != kNotOurWind) {
  422.         GetPort(&port);
  423.         SetPort(wind);
  424.         (*gDispatch[kind].activate)(wind, act);
  425.         SetPort(port);
  426.     }
  427. }
  428.  
  429.  
  430.  
  431. /*----------------------------------------------------------------------------
  432.     HandleUpdate
  433.     
  434.     Update a window.
  435.     
  436.     Entry:    wind = pointer to window.
  437. ----------------------------------------------------------------------------*/
  438.  
  439. void HandleUpdate (WindowPtr wind)
  440. {
  441.     GrafPtr port;
  442.     TWindowKind kind;
  443.     
  444.     kind = GetMyWindowKind(wind);
  445.     if (kind != kNotOurWind) {
  446.         GetPort(&port);
  447.         SetPort(wind);
  448.         BeginUpdate(wind);
  449.         EraseRect(&wind->portRect);
  450.         (*gDispatch[kind].update)(wind);
  451.         EndUpdate(wind);
  452.         SetPort(port);
  453.     }
  454. }
  455.  
  456.  
  457.  
  458. /*----------------------------------------------------------------------------
  459.     HandleMouseDown 
  460.     
  461.     Handle mouse down events.
  462.     
  463.     Entry:    ev = pointer to event record.
  464.     
  465.     Exit:    function result = error code.
  466. ----------------------------------------------------------------------------*/
  467.  
  468. static OSErr HandleMouseDown (EventRecord *ev)
  469. {
  470.     WindowPtr front, wind;
  471.     TWindowKind frontKind, kind;
  472.     short part;
  473.     GrafPtr port;
  474.     Point where;
  475.     short modifiers;
  476.     OSErr err = noErr;
  477.  
  478.     front = FrontWindow();
  479.     frontKind = GetMyWindowKind(front);
  480.     part = FindWindow(ev->where, &wind);
  481.     kind = GetMyWindowKind(wind);
  482.     where = ev->where;
  483.     modifiers = ev->modifiers;
  484.     
  485.     if (gLongOperation && part != inMenuBar && frontKind != kStatus) return noErr; 
  486.     
  487.     switch (part) {
  488.     
  489.         case inMenuBar:
  490.         
  491.             if (gLongOperation) SetMenusTo(kAppleOnlyAboutDisabled, 0, 0, 0, 0, 0);
  492.             err = DoCommand(MenuSelect(where), modifiers);
  493.             break;
  494.             
  495.         case inSysWindow:
  496.         
  497.             SystemClick(ev, wind);
  498.             break;
  499.             
  500.         case inDrag:
  501.         
  502.             if (front != wind && (frontKind == kStatus || frontKind == kDialog)) {
  503.                 SysBeep(0);
  504.             } else {
  505.                 HandleDrag(wind, where);
  506.             }
  507.             break;
  508.             
  509.         case inGrow:
  510.         
  511.             err = HandleGrow(wind, where);
  512.             break;
  513.             
  514.         case inGoAway:
  515.         
  516.             if (TrackGoAway(wind, where)) err = DoClose(wind);
  517.             break;
  518.             
  519.         case inZoomIn:
  520.         case inZoomOut:
  521.         
  522.             if (TrackBox(wind, where, part)) err = DoZoom(wind, part);
  523.             break;
  524.             
  525.         case inContent:
  526.         
  527.             GetPort(&port);
  528.             SetPort(wind);
  529.             GlobalToLocal(&where);
  530.             if (front == wind) {
  531.                 if (kind != kNotOurWind)
  532.                     err = (*gDispatch[kind].mouse)(wind, where, modifiers);
  533.             } else {
  534.                 if (frontKind != kStatus && frontKind != kDialog) {
  535.                     if (Draggable(wind, where, modifiers)) {
  536.                         err = (*gDispatch[kind].mouse)(wind, where, modifiers);
  537.                         gMouseDownWindow = wind;
  538.                     } else {
  539.                         SelectWindow(wind);
  540.                     }
  541.                 } else {
  542.                     SysBeep(0);
  543.                 }
  544.             }
  545.             SetPort(port);
  546.             break;
  547.             
  548.     }
  549.     
  550.     return err;
  551.     
  552. }
  553.  
  554.  
  555.  
  556. /*----------------------------------------------------------------------------
  557.     HandleMouseUp 
  558.     
  559.     Handle mouse up events.
  560.     
  561.     Entry:    ev = pointer to event record.
  562.     
  563.     Exit:    function result = error code.
  564. ----------------------------------------------------------------------------*/
  565.  
  566. static OSErr HandleMouseUp (EventRecord *ev)
  567. {
  568.     WindowPtr wind = nil;
  569.     short part;
  570.     TWindowKind frontKind;
  571.     
  572.     if (gMouseDownWindow == nil) return noErr;
  573.     frontKind = GetMyWindowKind(FrontWindow());
  574.     if (frontKind == kDialog || frontKind == kStatus) goto exit;
  575.     part = FindWindow(ev->where, &wind);
  576.     if (wind == gMouseDownWindow) SelectWindow(wind);
  577.  
  578. exit:
  579.  
  580.     gMouseDownWindow = nil;
  581.     return noErr;
  582. }
  583.  
  584.  
  585.  
  586. /*----------------------------------------------------------------------------
  587.     HandleKey 
  588.     
  589.     Handle key down events.
  590.     
  591.     Entry:    ev = pointer to event record.
  592.     
  593.     Exit:    function result = error code.
  594. ----------------------------------------------------------------------------*/
  595.  
  596. static OSErr HandleKey (EventRecord *ev)
  597. {
  598.     unsigned char theChar;
  599.     unsigned char theKey;
  600.     short modifiers;
  601.     long menuCmd;
  602.     WindowPtr wind;
  603.     TWindowKind kind;
  604.     GrafPtr port;
  605.     OSErr err = noErr;
  606.     
  607.     wind = FrontWindow();
  608.     kind = GetMyWindowKind(wind);
  609.     theChar = ev->message & charCodeMask;
  610.     theKey = (ev->message & keyCodeMask) >> 8;
  611.     modifiers = ev->modifiers;
  612.     
  613.     /*    Map F1,2,3,4 to Undo, Cut, Copy, Paste */
  614.     
  615.     if (theKey == 0x7A) {
  616.         modifiers = cmdKey;
  617.         theChar = 'Z';
  618.     } else if (theKey == 0x78) {
  619.         modifiers = cmdKey;
  620.         theChar = 'X';
  621.     } else if (theKey == 0x63) {
  622.         modifiers = cmdKey;
  623.         theChar = 'C';
  624.     } else if (theKey == 0x76) {
  625.         modifiers = cmdKey;
  626.         theChar = 'V';
  627.     }
  628.     
  629.     if (gLongOperation && kind != kStatus) {
  630.         if (theKey == escapeKeyCode || (modifiers & cmdKey) != 0 && theChar == '.') 
  631.             gCancel = true;
  632.         return noErr;
  633.     }
  634.     
  635.     #ifdef kDevelopmentVersion
  636.         if (!gLongOperation && (modifiers & cmdKey) != 0 && (modifiers & optionKey) != 0) {
  637.             if (theKey == 29) { /* cmd-opt-0 */
  638.                 DebugStr("\pYou asked for it!");
  639.                 return noErr;
  640.             }
  641.             if (theKey == 20) { /* cmd-opt-3 */
  642.                 return DisplayArticleCache();
  643.             }
  644.             if (theKey == 21) { /* cmd-opt-4 */
  645.                 FlushArticleCache();
  646.                 return noErr;
  647.             }
  648.             if (theKey == 23) { /* cmd-opt-5 */
  649.                 CompactArticleCache();
  650.                 return noErr;
  651.             }
  652.         }
  653.     #endif
  654.         
  655.     if (!gLongOperation && (modifiers & cmdKey) != 0) {
  656.         if ((modifiers & optionKey) != 0) {
  657.             if (theKey == 40) theChar = 'K';
  658.             if (theKey == 37) theChar = 'L';
  659.             if (theKey == 15) theChar = 'R';
  660.             if (theKey == 01) theChar = 'S';
  661.             if (theKey == 11) theChar = 'B';
  662.         }
  663.         menuCmd = MenuKey(theChar);
  664.         if (HiWord(menuCmd) != 0) return DoCommand(menuCmd, modifiers);
  665.     } 
  666.     
  667.     if (!gLongOperation) {
  668.         if (theChar == helpKey ||
  669.             (modifiers & cmdKey) != 0 && (theChar == '?' || theChar == '/'))
  670.         {
  671.             err = OpenFirstHelpTopicWindow();
  672.             return err;
  673.         }
  674.     }
  675.     
  676.     if (kind != kNotOurWind) {
  677.         if (!gLongOperation) ObscureCursor();
  678.         GetPort(&port);
  679.         SetPort(wind);
  680.         err = (*gDispatch[kind].key)(wind, theChar, theKey, modifiers);
  681.         SetPort(port);
  682.     }
  683.     
  684.     return err;
  685. }
  686.  
  687.  
  688.  
  689. /*----------------------------------------------------------------------------
  690.     HandleOSEvt 
  691.     
  692.     Handle OS events (suspend and resume).
  693.     
  694.     Entry:    ev = pointer to event record.
  695. ----------------------------------------------------------------------------*/
  696.  
  697. static void HandleOSEvt (EventRecord *ev)
  698. {
  699.     WindowPtr wind;
  700.     Boolean resume;
  701.  
  702.     if (((ev->message >> 24) & 0xff) != suspendResumeMessage) return;
  703.     SetCursor(&qd.arrow);
  704.     wind = FrontWindow();
  705.     resume = (ev->message & 1) == resumeFlag;
  706.     gInBackground = !resume;
  707.     HandleActivate(wind, resume);
  708.     if (resume) AdjustWindowTitlesOnResume();
  709. }
  710.  
  711.  
  712.  
  713. /*----------------------------------------------------------------------------
  714.     HandleIdle 
  715.     
  716.     Handle idle tasks.
  717.     
  718.     Exit:    cursorRgn = cursor region for WaitNextEvent mouse moved events.
  719. ----------------------------------------------------------------------------*/
  720.  
  721. void HandleIdle (RgnHandle cursorRgn)
  722. {
  723.     WindowPtr wind;
  724.     TWindowKind kind;
  725.     GrafPtr port;
  726.     unsigned long windEnabled;
  727.     Point where;
  728.     
  729.     NetIdle();
  730.     NntpIdle();
  731.     
  732.     RebuildWindowsMenu();
  733.     
  734.     wind = FrontWindow();
  735.     kind = GetMyWindowKind(wind);
  736.  
  737.     SetRectRgn(cursorRgn, -0x7fff, -0x7fff, 0x7fff, 0x7fff);
  738.     
  739.     if (kind == kNotOurWind) {
  740.         SetCursor(&qd.arrow);
  741.         if (IsDAWindow(wind)) {
  742.             SetMenusTo(kAppleAllEnabled, kDAFileEnabled, kDAEditEnabled, 
  743.                 kDANewsEnabled, kDASpecialEnabled,kDAWindEnabled);
  744.         } else if (!gStartupOK) {
  745.             windEnabled = wind == nil ? 0 : kStartupBadWindEnabled;
  746.             SetMenusTo(kAppleAllEnabled, kStartupBadFileEnabled, kStartupBadEditEnabled,
  747.                 kStartupBadNewsEnabled, kStartupBadSpecialEnabled, windEnabled);
  748.         } else if (wind == nil) {
  749.             SetMenusTo(kAppleAllEnabled, kNoneFileEnabled, kNoneEditEnabled, 
  750.                 kNoneNewsEnabled, kNoneSpecialEnabled, kNoneWindEnabled);
  751.         }
  752.     } else {
  753.         GetPort(&port);
  754.         SetPort(wind);
  755.         (*gDispatch[kind].idle)(wind, cursorRgn);
  756.         if (!gInBackground && HMGetBalloons() && !HMIsBalloon()) {
  757.             GetMouse(&where);
  758.             if (PtInRect(where, &wind->portRect)) (*gDispatch[kind].help)(wind, where);
  759.         }
  760.         SetPort(port);
  761.     }
  762.     AdjustCycleWindowsCommand();
  763.     AdjustMenuHelpBalloons(false);
  764.     AdjustHelpMenu();
  765. }
  766.  
  767.  
  768.  
  769. /*----------------------------------------------------------------------------
  770.     HandleEvent
  771.     
  772.     Handle an event.
  773.     
  774.     Entry:    ev = pointer to event.
  775. ----------------------------------------------------------------------------*/
  776.  
  777. void HandleEvent (EventRecord *ev)
  778. {
  779.     WindowPtr front;
  780.     WindowPeek peek;
  781.     Boolean isDialog = false;
  782.     Point thisPoint;
  783.     OSErr err = noErr;
  784.  
  785.     front = FrontWindow();
  786.     if (front != nil) {
  787.         peek = (WindowPeek)front;
  788.         if (peek->windowKind == dialogKind) isDialog = true;
  789.     }
  790.     
  791.     if (isDialog) gLongOperation = false;
  792.  
  793.     switch (ev->what) {
  794.         case activateEvt:
  795.             HandleActivate((WindowPtr)ev->message, (ev->modifiers & activeFlag) != 0);
  796.             break;
  797.         case updateEvt:
  798.             HandleUpdate((WindowPtr)ev->message);
  799.             break;
  800.         case mouseDown:
  801.             err = HandleMouseDown(ev);
  802.             break;
  803.         case mouseUp:
  804.             err = HandleMouseUp(ev);
  805.             break;
  806.         case keyDown:
  807.         case autoKey:
  808.             err = HandleKey(ev);
  809.             break;
  810.         case osEvt:
  811.             HandleOSEvt(ev);
  812.             break;
  813.         case kHighLevelEvent:
  814.             MyAEProcessAppleEvent(ev);
  815.             gLongOperation = false;
  816.             break;
  817.         case diskEvt:
  818.             if ((ev->message & 0xffff0000) != 0) {
  819.                 DILoad();
  820.                 SetPt(&thisPoint, 120, 120);
  821.                 DIBadMount(thisPoint, ev->message);
  822.                 DIUnload();
  823.             }
  824.             break;
  825.     }
  826.     
  827.     ReportSystemError(err);
  828. }
  829.  
  830.  
  831.  
  832. /*----------------------------------------------------------------------------
  833.     Quit
  834.     
  835.     Close windows prior to quitting.
  836.     
  837.     Exit:    function result = true if OK to quit, false if error or
  838.                 canceled by user.
  839. ----------------------------------------------------------------------------*/
  840.  
  841. static Boolean Quit (void)
  842. {
  843.     WindowPtr wind;
  844.     Str255 fullGroupWindowFont;
  845.     OSErr err = noErr;
  846.     Boolean fullGroupListWasVisible;
  847.     DialogPtr dlg;
  848.     short item;
  849.     
  850.     fullGroupListWasVisible = gFullGroupWindow != nil &&
  851.         ((WindowPeek)gFullGroupWindow)->visible;
  852.     
  853.     while (true) {
  854.         wind = FrontWindow();
  855.         while (wind != nil && GetMyWindowKind(wind) == kNotOurWind)
  856.             wind = (WindowPtr)((WindowPeek)wind)->nextWindow;
  857.         if (wind == nil) break;
  858.         err = DoClose(wind);
  859.         if (err == userCanceledErr) goto exit1;
  860.         if (err != noErr) {
  861.             ReportSystemError(err);
  862.             err = MyGetNewDialog(kErrorDuringQuitDlg, kErrorDuringQuitDlgQuitItem, cancel, &dlg);
  863.             if (err != noErr) goto exit;
  864.             SysBeep(0);
  865.             MyModalDialog(dlg, gDialogFilterUPP, &item);
  866.             err = DoClose(dlg);
  867.             if (err != noErr) goto exit;
  868.             if (item == kErrorDuringQuitDlgQuitItem) {
  869.                 break;
  870.             } else {
  871.                 goto exit1;
  872.             }
  873.         }
  874.     }
  875.     
  876.     if (gFullGroupWindow != nil) {
  877.         MyICReadSharedPrefs(kICListFont);
  878.         gPrefs.fullGroupListVisible = fullGroupListWasVisible;
  879.         GetFontName(gFullGroupWindow->txFont, fullGroupWindowFont);
  880.         if (gPrefs.listSize != gFullGroupWindow->txSize ||
  881.             !EqualString(gPrefs.listFont, fullGroupWindowFont, false, true))
  882.                 gPrefs.maxGroupNameWidth = 0;
  883.     }
  884.     
  885.     return true;
  886.     
  887. exit:
  888.  
  889.     ReportSystemError(err);
  890.     
  891. exit1:
  892.  
  893.     if (gFullGroupWindow != nil && fullGroupListWasVisible &&
  894.         !((WindowPeek)gFullGroupWindow)->visible) 
  895.     {
  896.         MyShowWindow(gFullGroupWindow);
  897.         SetWindowsMenuShowHideFullGroupList(false);
  898.     }
  899.     return false;
  900. }
  901.  
  902.  
  903.  
  904. /*----------------------------------------------------------------------------
  905.     MainEvent 
  906.     
  907.     Main event loop.
  908. ----------------------------------------------------------------------------*/
  909.  
  910. static void MainEvent (void)
  911. {
  912.     EventRecord ev;
  913.     RgnHandle cursorRgn, rgn;
  914.     Boolean gotEvt;
  915.     WindowPtr wind;
  916.     Boolean memOK;
  917.     static Boolean haveNotifiedLowMemory = false;
  918.     OSErr err = noErr;
  919.     long sleep;
  920.     TWindowKind kind;
  921.     
  922.     cursorRgn = NewRgn();
  923.     
  924.     while (!gDone) {
  925.     
  926.         wind = MyFrontWindow();
  927.         if (GetMyWindowKind(wind) == kStatus) DoClose(wind);
  928.     
  929.         if (gLongOperation && gInBackground) NotifyUser();
  930.     
  931.         memOK = RecoverReserveMemory();
  932.         if (memOK) {
  933.             haveNotifiedLowMemory = false;
  934.         } else if (!haveNotifiedLowMemory) {
  935.             CautionMessageNumber(kStrMemoryLow);
  936.             haveNotifiedLowMemory = true;
  937.         }
  938.         EndCriticalMemorySequence(false);
  939.         
  940.         HandleIdle(cursorRgn);
  941.     
  942.         gCancel = gLongOperation = gInDialog = false;
  943.         gDragPostProcessor = nil;
  944.         
  945.         if (gInBackground) {
  946.             /* sleep = 0x7fffffff; - doesn't work: drag text to message
  947.                wind while in background, window doesn't update! */
  948.             sleep = GetCaretTime();
  949.             rgn = nil;
  950.         } else {
  951.             kind = GetMyWindowKind(FrontWindow());
  952.             if (kind == kGroup || kind == kSubject) {
  953.                 /*sleep = 0x7fffffff;*/
  954.                 sleep = GetCaretTime();
  955.                 rgn = nil;
  956.             } else {
  957.                 sleep = GetCaretTime();
  958.                 rgn = cursorRgn;
  959.             }
  960.         }
  961.         
  962.         gotEvt = WaitNextEvent(everyEvent, &ev, sleep, rgn);
  963.         
  964.         if (gotEvt) {
  965.             gPrevEvent = gCurEvent;
  966.             gCurEvent = ev;
  967.             HandleEvent(&ev);
  968.         }
  969.                 
  970.         if (gDragErr != noErr) {
  971.             ReportSystemError(gDragErr);
  972.             gDragErr = noErr;
  973.         }
  974.         
  975.         if (gDragPostProcessor != nil) {
  976.             err = (*gDragPostProcessor)();
  977.             ReportSystemError(err);
  978.         }
  979.         
  980.         if (gDone) gDone = Quit();
  981.         
  982.     }
  983. }
  984.  
  985.  
  986.  
  987. /*----------------------------------------------------------------------------
  988.     GiveTime
  989.     
  990.     Give time to other processes during long operations. Check for 
  991.     user cancels. Spin the beachball cursor.
  992.     
  993.     Entry:    waiting = true if waiting for net driver or something else - 
  994.                 yield CPU continuously to other processes while
  995.                 waiting.
  996.             waiting = false if busy doing some kind of computation -
  997.                 yield CPU to other processes only once every 5 ticks.
  998.     
  999.     Exit:    function result = error code (userCanceledErr if canceled
  1000.                 by user, else noErr).
  1001. ----------------------------------------------------------------------------*/
  1002.  
  1003. OSErr GiveTime (Boolean waiting)
  1004. {
  1005.     EventRecord ev;
  1006.     Boolean gotEvt;
  1007.     Point where;
  1008.     WindowPtr wind;
  1009.     TWindowKind kind;
  1010.     GrafPtr port;
  1011.     static long nextTime = 0;
  1012.     static DialogPtr waitForDNRDlg;
  1013.         
  1014.     if (!gLongOperation) {
  1015.         HiliteMenu(0);
  1016.         SpinCursor(0);
  1017.         ShowCursor();
  1018.         gLongOperation = true;
  1019.     }
  1020.  
  1021.     if (TickCount() >= nextTime) {
  1022.         #ifdef powerc
  1023.             SpinCursor(32);    /* joke - spin cursor twice as fast on Power Macs */
  1024.         #else
  1025.             SpinCursor(16);
  1026.         #endif
  1027.         nextTime = TickCount() + 5;
  1028.         waiting = true;
  1029.     }
  1030.     
  1031.     if (waiting) {
  1032.         gotEvt = WaitNextEvent(everyEvent & ~highLevelEventMask & ~diskMask, 
  1033.             &ev, 0, nil);
  1034.         if (gotEvt) HandleEvent(&ev);
  1035.     }
  1036.     
  1037.     if (gCancel && waitForDNRDlg == nil && NetMacTCPDNROperationInProgress()) {
  1038.         MyGetNewDialog(kWaitForDNRDlg, 0, 0, &waitForDNRDlg);
  1039.         if (waitForDNRDlg != nil) {
  1040.             RestoreMovableModalDialogPosition(waitForDNRDlg, gPrefs.waitForDNRLoc);
  1041.             MyShowWindow(waitForDNRDlg);
  1042.         }
  1043.     }
  1044.     
  1045.     if (waitForDNRDlg != nil && !NetMacTCPDNROperationInProgress()) {
  1046.         SaveMovableModalDialogPosition(waitForDNRDlg, &gPrefs.waitForDNRLoc);
  1047.         DoClose(waitForDNRDlg);
  1048.         waitForDNRDlg = nil;
  1049.     }
  1050.     
  1051.     if (!gInBackground && HMGetBalloons() && !HMIsBalloon()) {
  1052.         wind = FrontWindow();
  1053.         kind = GetMyWindowKind(wind);
  1054.         if (kind != kNotOurWind) {
  1055.             GetPort(&port);
  1056.             SetPort(wind);
  1057.             GetMouse(&where);
  1058.             if (PtInRect(where, &wind->portRect)) (*gDispatch[kind].help)(wind, where);
  1059.             SetPort(port);
  1060.         }
  1061.     }
  1062.     
  1063.     AdjustMenuHelpBalloons(false);
  1064.     AdjustHelpMenu();
  1065.     
  1066.     return gCancel ? userCanceledErr : noErr;
  1067. }
  1068.  
  1069. static OSErr GiveTimeDuringNetworkOperation (void)
  1070. {
  1071.     #ifdef testingOT
  1072.         long xxx;
  1073.         Delay(OTDelay, &xxx);
  1074.     #endif
  1075.     
  1076.     return GiveTime(true);
  1077. }
  1078.  
  1079. static OSErr GiveTimeDuringCPUOperation (void)
  1080. {
  1081.     return GiveTime(false);
  1082. }
  1083.  
  1084.  
  1085.  
  1086. /*----------------------------------------------------------------------------
  1087.     ForceCodeHigh 
  1088.         
  1089.     Load all unloaded CODE resources, force them to high memory, 
  1090.     and lock them.
  1091.     
  1092.     Does nothing in Power PC mode.
  1093. ----------------------------------------------------------------------------*/
  1094.  
  1095. static void ForceCodeHigh (void)
  1096. {
  1097.     Handle h;
  1098.     short refNum, curRefNum, i, rID;
  1099.     ResType rType;
  1100.     Str255 rName;
  1101.     OSErr err = noErr;
  1102.     
  1103.     #ifdef powerc
  1104.         return;
  1105.     #endif
  1106.     
  1107.     h = GetResource('CODE', 1);
  1108.     if (h == nil) return;
  1109.     refNum = HomeResFile(h);
  1110.     curRefNum = CurResFile();
  1111.     UseResFile(refNum);
  1112.     SetResLoad(false);
  1113.     for (i = 1; ; i++) {
  1114.         h = Get1IndResource('CODE', i);
  1115.         if (h == nil) break;
  1116.         GetResInfo(h, &rID, &rType, rName);
  1117.         if (rID != 0) {
  1118.             LoadResource(h);
  1119.             HLockHi(h);
  1120.         }
  1121.     }
  1122.     SetResLoad(true);
  1123.     UseResFile(curRefNum);
  1124.     
  1125.     /* Force segment loader to know that ANSI seg is loaded. */
  1126.     
  1127.     strlen("");
  1128. }
  1129.  
  1130.  
  1131.  
  1132. /*----------------------------------------------------------------------------
  1133.     Init 
  1134.         
  1135.     Initialize the program.
  1136.     
  1137.     Exit:    function result = true if startup OK up through establishing a
  1138.                 connection with the news server and getting the full
  1139.                 group list (either from the prefs file or from the
  1140.                 server), false otherwise.
  1141. ----------------------------------------------------------------------------*/
  1142.  
  1143. static Boolean Init (void)
  1144. {
  1145.     EventRecord ev;
  1146.     AppleEvent firstEvent = {0, nil};
  1147.     AppleEvent firstReply = {0, nil};
  1148.     CStr255 msg;
  1149.     Boolean mightHaveNewGroups = true;
  1150.     short sizeofTPrefRec;
  1151.     long systemVersion, dragMgrAttr;
  1152.     OSErr err = noErr;
  1153.     Boolean savedNoNewConnection;
  1154.     Handle mbar;
  1155.     CStr255 fmt;
  1156.     ProcessSerialNumber myPSN, frontPSN;
  1157.     Boolean inFront;
  1158.     TGroup **newGroupsArray = nil;
  1159.     short numNewGroups = 0;
  1160.     WindowPtr wind;
  1161.     Handle h;
  1162.     DialogPtr dlg;
  1163.     short item;
  1164.     
  1165.     /* Initialize the toolbox. */
  1166.  
  1167.     InitGraf(&qd.thePort);
  1168.     InitFonts();
  1169.     InitWindows();
  1170.     InitMenus();
  1171.     TEInit();
  1172.     InitDialogs(nil);
  1173.     InitCursor();
  1174.  
  1175.     /* Allocate a 1K memory block, force it to the top of the heap, and lock it.
  1176.        This block is not used for anything - it is put at the top of the heap
  1177.        as a sacrifice because sometimes MacSLIP's VBL task trashes the end of 
  1178.        the heap. Note: This problem was fixed in MacSLIP 2.0.6. */
  1179.      
  1180.     h = NewHandle(1000);
  1181.     if (h != nil) {
  1182.         MoveHHi(h);
  1183.         HLock(h);
  1184.     }
  1185.     
  1186.     /* Check for System 7.0 or later. */
  1187.  
  1188.     if (!MyTrapAvailable(_Gestalt)) {
  1189.         StopAlert(kNeedSystem7AlertID, nil);
  1190.         ExitToShell();
  1191.     }
  1192.     err = Gestalt(gestaltSystemVersion, &systemVersion);
  1193.     if (err != noErr || systemVersion < 0x0700) {
  1194.         StopAlert(kNeedSystem7AlertID, nil);
  1195.         ExitToShell();
  1196.     }
  1197.     
  1198.     /* In 68k mode, preload and force all CODE resources to locked high memory.
  1199.        This strategy is used instead of unloadseg calls to avoid fragmenting
  1200.        the heap. */
  1201.  
  1202.     ForceCodeHigh();
  1203.     
  1204.     /* Intialize the memory utilities. */
  1205.     
  1206.     InitMemUtil(40000, 40000);
  1207.     
  1208.     /* Initialize the window handling module method dispatch tables. */
  1209.     
  1210.     InitGroupDispatchTable();
  1211.     InitSubjectDispatchTable();
  1212.     InitArticleDispatchTable();
  1213.     InitMessageDispatchTable();
  1214.     InitTextDispatchTable();
  1215.     InitHelpDispatchTable();
  1216.     InitStatusDispatchTable();
  1217.     InitDialogDispatchTable();
  1218.     InitDummyDispatchTable();
  1219.     
  1220.     /* Intialize miscellaneous UPPs. */
  1221.     
  1222.     sfutil_InitUPP();
  1223.     print_InitUPP();
  1224.     prefsdlog_InitUPP();
  1225.     ldef_InitUPP();
  1226.     
  1227.     /* Create a pool of 50 window records in locked high memory, again to
  1228.        avoid later heap fragmentation. */
  1229.     
  1230.     err = InitializeWindowRecordStorage(50);
  1231.     if (err != noErr) goto exit1;
  1232.     
  1233.     /* Initialize the spinning beachball cursor. */
  1234.     
  1235.     InitCursorCtl(nil);
  1236.     
  1237.     /* Flush the event queue. */
  1238.  
  1239.     FlushEvents(everyEvent,0);
  1240.     EventAvail(everyEvent, &ev);
  1241.     
  1242.     /* Check for Drag Manager 1.1 or later and TextEdit outline hilite feature. */
  1243.  
  1244.     err = Gestalt(gestaltDragMgrAttr, &dragMgrAttr);
  1245.     gHaveDragMgr = err == noErr && (dragMgrAttr & (1L << gestaltDragMgrPresent)) != 0
  1246.         && (dragMgrAttr & (1L << gestaltDragMgrFloatingWind)) != 0;
  1247.     #ifdef powerc
  1248.         gHaveDragMgr = gHaveDragMgr && 
  1249.             (dragMgrAttr & (1L << gestaltPPCDragLibPresent)) != 0
  1250.             && (long)InstallTrackingHandler != kUnresolvedSymbolAddress;
  1251.     #endif
  1252.     gHaveTEOutlineHilite = HaveTEOutlineHiliteFeature();
  1253.     
  1254.     /* Get the desktop extent and ibeam and watch cursors. Initialize SpinCursor. */
  1255.     
  1256.     gDesktopExtent = (**GetGrayRgn()).rgnBBox;
  1257.     gIBeamCurs = **(GetCursor(iBeamCursor));
  1258.     gWatchCurs = **(GetCursor(watchCursor));
  1259.     SpinCursor(0);
  1260.     
  1261.     /* Create and draw the menu bar. */
  1262.     
  1263.     mbar = GetNewMBar(kMBarID);
  1264.     SetMenuBar(mbar);
  1265.     AppendResMenu(GetMenuHandle(kAppleMenu), 'DRVR');
  1266.     DrawMenuBar();
  1267.     InitHelpMenu();
  1268.     
  1269.     /* Figure out whether we were launched in the background or foreground. */
  1270.  
  1271.     GetCurrentProcess(&myPSN);
  1272.     GetFrontProcess(&frontPSN);
  1273.     SameProcess(&myPSN, &frontPSN, &inFront);
  1274.     gInBackground = !inFront;
  1275.     
  1276.     /* Check to see if we screwed up the size of the prefs struct. This is
  1277.        for sanity testing during development. */
  1278.  
  1279.     sizeofTPrefRec = sizeof(TPrefRec);
  1280.     if (sizeofTPrefRec != kTPrefRecSize) {
  1281.         GetCString(kStrSizeofTPrefRecBadFmt, fmt);
  1282.         sprintf(msg, fmt, sizeofTPrefRec, kTPrefRecSize);
  1283.         ErrorMessage(msg);
  1284.         ExitToShell();
  1285.     }
  1286.     
  1287.     /* Initialize Apple event handling. */
  1288.  
  1289.     err = InitializeAppleEvents(&firstEvent, &firstReply);
  1290.     if (err != noErr) goto exit1;
  1291.     
  1292.     /* Read the preferences file */
  1293.     
  1294.     err = ReadPrefs(&firstEvent);
  1295.     savedNoNewConnection = gPrefs.noNewConnection;
  1296.     if (err != noErr) goto exit1;
  1297.     
  1298.     /* Open the log file. */
  1299.  
  1300.     if (gPrefs.logActionsToFile) OpenLogFile();
  1301.     
  1302.     /* Open network driver (MacTCP or Open Transport). */
  1303.  
  1304.     err = DisplayStatusMessageNumber(NetHaveOT() ? kStrOpeningOTStatusMsg : 
  1305.         kStrOpeningMacTCPStatusMsg);
  1306.     if (err != noErr) goto exit1;
  1307.  
  1308.     err = NetInit(GiveTimeDuringNetworkOperation, Log, 2);
  1309.     if (err != noErr) goto exit1;
  1310.     
  1311.     #ifdef testingOT
  1312.         TestOT();
  1313.     #endif
  1314.     
  1315.     /* Initialize the nntp.c module. */
  1316.     
  1317.     NntpInit(GiveTimeDuringCPUOperation);
  1318.     
  1319.     /* Open the initial connection to the news server. */
  1320.     
  1321.     gPrefs.noNewConnection = true;
  1322.     while (true) {
  1323.         err = StartNNTP();
  1324.         if (err == noErr) break;
  1325.         ReportSystemError(err);
  1326.         err = MyGetNewDialog(kRetryConnectID, ok, cancel, &dlg);
  1327.         if (err != noErr) goto exit1;
  1328.         RestoreMovableModalDialogPosition(dlg, gPrefs.retryConnectLoc);
  1329.         MyMovableModalDialog(dlg, DialogFilter, &item);
  1330.         SaveMovableModalDialogPosition(dlg, &gPrefs.retryConnectLoc);
  1331.         err = DoClose(dlg);
  1332.         if (err != noErr) goto exit1;
  1333.         if (item == cancel) goto exit1;
  1334.     }
  1335.     
  1336.     /* Get the full group list from the server if necessary. */
  1337.     
  1338.     if (gNumGroups == 0) {
  1339.         err = DoRebuildFullGroupList();
  1340.         if (err != noErr) goto exit1;
  1341.         mightHaveNewGroups = false;
  1342.     }
  1343.     
  1344.     /* Create the full group window. */
  1345.     
  1346.     err = MakeFullGroupWindow(gFullGroupArray, gNumGroups, &gFullGroupWindow);
  1347.     if (err != noErr) goto exit1;
  1348.     
  1349.     /* Check for new groups if necessary and requested by the user. */
  1350.     
  1351.     if (mightHaveNewGroups && gPrefs.checkForNewGroups) {
  1352.         err = CheckForNewGroups(&newGroupsArray, &numNewGroups);
  1353.         if (err != noErr && err != userCanceledErr) goto exit2;
  1354.         gCancel = false;
  1355.     }
  1356.     
  1357.     /* Auto-fetch a newsrc file from a remote host if requested by the user. */
  1358.  
  1359.     if (gPrefs.autoFetchNewsrc) {
  1360.         err = AutoFetchNewsrcFromHost();
  1361.         if (err != noErr && err != userCanceledErr) goto exit2;
  1362.         gCancel = false;
  1363.     }
  1364.     
  1365.     /* Handle the initial Apple event. */
  1366.     
  1367.     MyAEResumeTheCurrentEvent(&firstEvent, &firstReply, 
  1368.         (AEEventHandlerUPP)kAEUseStandardDispatch, 0);
  1369.     firstEvent.dataHandle = nil;
  1370.     
  1371.     /* If there are new groups, create the new groups window. */
  1372.     
  1373.     if (numNewGroups > 0) {
  1374.         err = MakeNewGroupsWindow(newGroupsArray, numNewGroups, &wind);
  1375.         if (err != noErr) goto exit2;
  1376.     }
  1377.     
  1378.     gPrefs.noNewConnection = savedNoNewConnection;
  1379.     ResetNewsServerOptions();
  1380.     
  1381.     return true;
  1382.     
  1383. exit1:
  1384.  
  1385.     if (firstEvent.dataHandle != nil)
  1386.         MyAEResumeTheCurrentEvent(&firstEvent, &firstReply, 
  1387.             (AEEventHandlerUPP)kAENoDispatch, 0);
  1388.     EndNNTP();
  1389.     ReportSystemError(err);
  1390.     ErrorMessageNumber(kStrStartupError);
  1391.     gPrefs.noNewConnection = savedNoNewConnection;
  1392.     return false;
  1393.     
  1394. exit2:
  1395.  
  1396.     if (firstEvent.dataHandle != nil)
  1397.         MyAEResumeTheCurrentEvent(&firstEvent, &firstReply, 
  1398.             (AEEventHandlerUPP)kAENoDispatch, 0);
  1399.     ReportSystemError(err);
  1400.     gPrefs.noNewConnection = savedNoNewConnection;
  1401.     ResetNewsServerOptions();
  1402.     return true;
  1403. }
  1404.  
  1405.  
  1406.  
  1407. /*----------------------------------------------------------------------------
  1408.     Term 
  1409.     
  1410.     Terminate the program.
  1411. ----------------------------------------------------------------------------*/
  1412.  
  1413. static void Term (void)
  1414. {
  1415.     OSErr err = noErr;
  1416.  
  1417.     err = WritePrefs();
  1418.     ReportSystemError(err);
  1419.     DeleteTemporaryFiles(kNewsWatcherSignature);
  1420.     EndNNTP();
  1421.     NetTerm();
  1422.     if (gPrefs.logActionsToFile) CloseLogFile();
  1423.     MyICStop();
  1424.     AdjustMenuHelpBalloons(true);
  1425. }
  1426.  
  1427.  
  1428. /*----------------------------------------------------------------------------
  1429.     main 
  1430.     
  1431.     Main entry point.
  1432. ----------------------------------------------------------------------------*/
  1433.  
  1434. void main (void)
  1435. {
  1436.     short i;
  1437.  
  1438.     SetApplLimit(GetApplLimit() - 20000);
  1439.     MaxApplZone();
  1440.     for (i = 0; i < 20; i++) MoreMasters();
  1441.     gStartupOK = Init();
  1442.     gStartingUp = false;
  1443.     MainEvent();
  1444.     Term();
  1445. }
  1446.